package top.whysu.edevice.service.ezviz.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import top.whysu.edevice.constant.CodeConstant;
import top.whysu.edevice.constant.EzvizConstant;
import top.whysu.edevice.dto.ezviz.EzvizResponseDTO;
import top.whysu.edevice.dto.ezviz.child.*;
import top.whysu.edevice.dto.ezviz.device.*;
import top.whysu.edevice.dto.ezviz.token.TokenRequestDTO;
import top.whysu.edevice.dto.ezviz.token.TokenResponseDTO;
import top.whysu.edevice.exception.BusinessException;
import top.whysu.edevice.service.ezviz.EzvizHttpService;

import java.lang.reflect.Field;
import java.util.List;
import java.util.TreeMap;

@Service("EzvizApiServiceImpl")
public class EzvizHttpServiceImpl implements EzvizHttpService {
    private static final Logger LOGGER = LoggerFactory.getLogger(EzvizHttpServiceImpl.class);


    @Override
    public TokenResponseDTO getAccessToken(TokenRequestDTO accessTokenDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.GET_ACCESS_TOKEN, accessTokenDTO);
            if (responseDTO != null && EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())) {
                return JSON.parseObject(JSON.toJSONString(responseDTO.getData()), TokenResponseDTO.class);
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取AccessToken失败！"
                        + (responseDTO != null ? responseDTO.getMsg() + "(" + responseDTO.getCode() + ")" : ""));
            }
        } catch (BusinessException e) {
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, e.getMessage());
        } catch (Exception e) {
            LOGGER.error("获取AccessToken异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取AccessToken异常! ");
        }
    }

    @Override
    public GetLiveAddressResponseTO getLiveAddress(GetLiveAddressRequestDTO requestDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.GET_LIVE_ADDRESS, requestDTO);
            if (responseDTO != null && EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())) {
                return JSON.parseObject(JSON.toJSONString(responseDTO.getData()), GetLiveAddressResponseTO.class);
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取直播地址失败！"
                        + (responseDTO != null ? responseDTO.getMsg() + "(" + responseDTO.getCode() + ")" : ""));
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            LOGGER.error("获取直播地址异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取直播地址异常! ");
        }
    }

    @Override
    public void addDevice(EzvizDeviceAddDTO deviceAddDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.DEVICE_ADD, deviceAddDTO);
            if (responseDTO != null) {
                if (EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())
                        || EzvizConstant.Code.DEVICE_ALREADY_ADD_BY_MYSELF.equals(responseDTO.getCode())) {
                    // 添加成功
                } else {
                    throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "添加设备失败！"
                            + responseDTO.getMsg() + "(" + responseDTO.getCode() + ")");
                }
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "添加设备失败！萤石响应异常！");
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            LOGGER.error("添加设备异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "添加设备异常! ");
        }
    }

    @Override
    public void deleteDevice(EzvizDeviceDeleteDTO deviceDeleteDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.DEVICE_DELETE, deviceDeleteDTO);
            if (responseDTO != null ) {
                if (EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())
                        || EzvizConstant.Code.DEVICE_NOT_EXIST.equals(responseDTO.getCode())
                        || EzvizConstant.Code.DEVICE_NOT_BELONG_TO_YOU.equals(responseDTO.getCode())
                        || EzvizConstant.Code.DEVICE_SERIAL_ILLEGAL.equals(responseDTO.getCode())) {
                    // 删除成功
                } else {
                    throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "删除设备失败！"
                            + responseDTO.getMsg() + "(" + responseDTO.getCode() + ")");
                }
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "删除设备失败！萤石响应异常！");
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            LOGGER.error("删除设备异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "删除设备异常! ");
        }
    }

    @Override
    public void updateDeviceName(EzvizDeviceRenameDTO deviceRenameDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.DEVICE_RENAME, deviceRenameDTO);
            if (responseDTO != null && EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())) {
                // 修改成功
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "修改设备名称失败！"
                        + (responseDTO != null ? responseDTO.getMsg() + "(" + responseDTO.getCode() + ")" : ""));
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            LOGGER.error("修改设备名称异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "修改设备名称异常! ");
        }
    }

    @Override
    public ChildCreateResponseDTO createChildAccount(ChildCreateRequestDTO requestDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.LAPP_ACCOUNT_CREATE, requestDTO);
            if (requestDTO != null) {
                if (EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())){
                    // 响应成功
                    return JSON.parseObject(JSON.toJSONString(responseDTO.getData()), ChildCreateResponseDTO.class);
                } else if (EzvizConstant.Code.ACCOUNT_ALREADY_EXIST.equals(responseDTO.getCode())) {
                    // 如果响应子账号已存在的话，通过AccountName获取子账号的信息
                    ChildInfoRequestDTO infoRequestDTO = new ChildInfoRequestDTO();
                    infoRequestDTO.setAccessToken(requestDTO.getAccessToken());
                    infoRequestDTO.setAccountName(requestDTO.getAccountName());
                    ChildInfoResponseDTO infoResponseDTO = this.getChildAccountInfo(infoRequestDTO);
                    // 封装返回
                    ChildCreateResponseDTO childCreateResponseDTO = new ChildCreateResponseDTO();
                    childCreateResponseDTO.setAccountId(infoResponseDTO.getAccountId());
                    return childCreateResponseDTO;
                } else {
                    throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "创建子账号失败！" + responseDTO.getMsg() + "(" + responseDTO.getCode() + ")");
                }
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "创建子账号失败！");
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getCode(), e.getMessage());
        } catch (Exception e) {
            LOGGER.error("创建子账号异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "创建子账号异常! ");
        }
    }

    @Override
    public void deleteChildAccount(ChildDeleteRequestDTO requestDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.LAPP_ACCOUNT_DELETE, requestDTO);
            if (responseDTO != null) {
                if (EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())
                        || EzvizConstant.Code.ACCOUNT_DID_NOT_EXIST.equals(responseDTO.getCode())) {
                    // 响应成功，或者响应子账号不存在的话也当做删除成功
                } else {
                    throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "删除子账号失败！"
                            + responseDTO.getMsg() + "(" + responseDTO.getCode() + ")");
                }
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "删除子账号失败！");
            }
        } catch (BusinessException e) {
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, e.getMessage());
        } catch (Exception e) {
            LOGGER.error("删除子账号异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "删除子账号异常! ");
        }
    }

    @Override
    public ChildInfoResponseDTO getChildAccountInfo(ChildInfoRequestDTO requestDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.LAPP_ACCOUNT_INFO, requestDTO);
            if (responseDTO != null && EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())) {
                // 获取成功
                return JSON.parseObject(JSON.toJSONString(responseDTO.getData()), ChildInfoResponseDTO.class);
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取子账号信息失败！"
                        + (responseDTO != null ? responseDTO.getMsg() + "(" + responseDTO.getCode() + ")" : ""));
            }
        } catch (BusinessException e) {
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, e.getMessage());
        } catch (Exception e) {
            LOGGER.error("获取子账号信息异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取子账号信息异常! ");
        }
    }

    @Override
    public void childSetPolicy(ChildSetPolicyDTO policyDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.LAPP_ACCOUNT_SET_POLICY, policyDTO);
            if (responseDTO != null && EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())) {
                // 设置成功
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "设置子账号权限失败！"
                        + (responseDTO != null ? responseDTO.getMsg() + "(" + responseDTO.getCode() + ")" : ""));
            }
        } catch (BusinessException e) {
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, e.getMessage());
        } catch (Exception e) {
            LOGGER.error("设置子账号权限异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "设置子账号权限异常! ");
        }
    }

    @Override
    public ChildTokenResponseDTO getChildAccessToken(ChildTokenRequestDTO requestDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.LAPP_ACCOUNT_ACCESS_TOKEN, requestDTO);
            if (responseDTO != null && EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())) {
                return JSON.parseObject(JSON.toJSONString(responseDTO.getData()), ChildTokenResponseDTO.class);
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取子账户accessToken失败！"
                        + (responseDTO != null ? responseDTO.getMsg() + "(" + responseDTO.getCode() + ")" : ""));
            }
        } catch (BusinessException e) {
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, e.getMessage());
        } catch (Exception e) {
            LOGGER.error("获取子账户accessToken异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "获取子账户accessToken异常! ");
        }
    }

    @Override
    public void deviceAddToAccount(DeviceAddToChildDTO childDTO) {
        try {
            EzvizResponseDTO responseDTO = sendHttp(EzvizConstant.Api.DEVICE_ADD_TO_CHILE_ACCOUNT, childDTO);
            if (responseDTO != null && EzvizConstant.Code.SUCCESS.equals(responseDTO.getCode())) {
                // 添加成功
            } else {
                throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "添加设备到子账号失败！"
                        + (responseDTO != null ? responseDTO.getMsg() + "(" + responseDTO.getCode() + ")" : ""));
            }
        } catch (BusinessException e) {
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, e.getMessage());
        } catch (Exception e) {
            LOGGER.error("添加设备到子账号失败异常", e);
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "添加设备到子账号失败异常! ");
        }
    }


    /**
     * HTTP接口请求公安授权平台
     *
     * @param url  请求全url路径
     * @param data 请求参数
     * @return 返回结果
     */
    private <T> EzvizResponseDTO sendHttp(String url, T data) {
        HttpResponse httpResponse = null;
        try {
            LOGGER.info("请求萤石平台，请求路径：{}， 请求参数：{}", url, JSON.toJSONString(data));
            httpResponse = HttpRequest.post(url)
                    .contentType("application/x-www-form-urlencoded")
                    .header("Host", "open.ys7.com")
                    .form(objToMap(data))
                    .timeout(10 * 1000)
                    .execute();
        } catch (Exception e) {
            LOGGER.error("请求萤石平台发生异常", e);
        }
        if (httpResponse != null) {
            if (httpResponse.isOk()) {
                LOGGER.info("请求萤石平台成功,请求路径：{}\n 响应结果为：{}", url, httpResponse.toString());
                return JSONObject.parseObject(httpResponse.body(), EzvizResponseDTO.class);
            } else {
                LOGGER.error("请求萤石平台失败,请求路径：{} \n ，响应结果为：{}", url, httpResponse.toString());
                throw new BusinessException(EzvizConstant.Code.SERVER_ERROR, "请求萤石平台失败，响应码: " + httpResponse.getStatus());
            }
        } else {
            throw new BusinessException(EzvizConstant.Code.SERVER_ERROR, "请求萤石平台响应超时，请重试!");
        }
    }


    /**
     * 将对象转成TreeMap,属性名为key,属性值为value
     * @param object    对象
     * @return
     * @throws IllegalAccessException
     */
    private static TreeMap<String, Object> objToMap(Object object) throws IllegalAccessException {

        Class clazz = object.getClass();
        TreeMap<String, Object> treeMap = new TreeMap<String, Object>();

        while ( null != clazz.getSuperclass() ) {
            Field[] declaredFields1 = clazz.getDeclaredFields();

            for (Field field : declaredFields1) {
                String name = field.getName();

                // 获取原来的访问控制权限
                boolean accessFlag = field.isAccessible();
                // 修改访问控制权限
                field.setAccessible(true);
                Object value = field.get(object);
                // 恢复访问控制权限
                field.setAccessible(accessFlag);

                if (null != value && StringUtils.isNotBlank(value.toString())) {
                    //如果是List,将List转换为json字符串
                    if (value instanceof List) {
                        value = JSON.toJSONString(value);
                    }
                    treeMap.put(name, value);
                }
            }

            clazz = clazz.getSuperclass();
        }
        return treeMap;
    }
}
